<?php

define('cSESSION_STATUS_OPENED', 1);
define('cSESSION_STATUS_CLOSED', 2);
define('cSESSION_STATUS_PAUSED', 3);

final class C_SessionManager
{
	private static $_sess = "puto";
	
	private static $id;
	private static $data = array();
	private static $status = 'unknown';	
	
	const sess_name = 'CPHPSESS'; 
	const name_mod = 'c_sess';
	
	// protect class from being instantiated
	protected function __construct(){}
	
	static function SetHandlers()
	{
		ini_set('session.save_path', SITE_PATH.'tmp/session');
		session_name(self::sess_name);
		session_set_save_handler('C_SessionManager::Open',
								 'C_SessionManager::Close',
								 'C_SessionManager::Read',
								 'C_SessionManager::Write',
								 'C_SessionManager::Destroy',
								 'C_SessionManager::GarbageCollector'
		);
	}
	
	static function Edit( $key, $value )
	{
		self::StatusCheck();
		
		if( self::$status ==  cSESSION_STATUS_OPENED )
			$_SESSION[$key] = $value;
			
		if ( self::$status ==  cSESSION_STATUS_PAUSED )
			self::$data[$key] = $value;
	}
	
	static function Save()
	{
		self::StatusCheck();
		
		if( self::$status ==  cSESSION_STATUS_OPENED )
			self::Write(session_id());
			
		if( self::$status ==  cSESSION_STATUS_PAUSED )
			self::Write(self::$id);
	}
	
	static function Pause()
	{
		
		if( self::$status !=  cSESSION_STATUS_OPENED )
			Cogumelo::ServerError(__METHOD__."(): Cannot Pause non-opened Session.");
		
		// Check if the current session belongs to Cogumelo
		if(session_name() != self::sess_name)
			Cogumelo::ServerError(__METHOD__."(): The current Session does not belong to Cogumelo. Cannot Pause it.");
			
		self::$id = session_id();
		self::$data = $_SESSION;
		// destroy Cogumelo's session
		session_destroy();
		
		// to ensure session is resumed when the request ends
		self::$status = cSESSION_STATUS_PAUSED;
	}
	
	static function Resume()
	{
		if( self::$status != cSESSION_STATUS_PAUSED ) return false;
		
		// save current session (belongs to whom it belongs)
		session_write_close();
		
		// restart Cogumelo's session & cogumelo's handling system
		self::SetHandlers();
		
		session_id(self::$id);
		session_start();
		
		// clean $_SESSION superglobal & recover session data 
		//session_unset();
		if( !is_array(self::$data) )
			Cogumelo::Error('Extrange non-array error on '.__METHOD__);

			

			
		$_SESSION = self::$data;
		
		self::$status = cSESSION_STATUS_OPENED;
	}
	
	//////////////////////////////////////////
	// Internal use
	
	protected static function StatusCheck()
	{
		if( self::$status != cSESSION_STATUS_OPENED && self::$status != cSESSION_STATUS_PAUSED)
		{
			Cogumelo::ServerError(__METHOD__."(): Cogumelo's session is not active. Cannot edit or save it. current_status=".self::$status."backtrace:<br/>".print_r(debug_backtrace()));
			exit;
		}
	}
	
	protected static function session_file($session_id)
	{
		return session_save_path().'/'.self::name_mod.$session_id;
	}
	
	//////////////////////////////////////////
	// User-level session storage functions
	
	public static function Open($save_path, $session_name)
	{
		// check session save path
		if( !file_exists($save_path) ) Cogumelo::Error("Session save path does not exist: '$save_path'", 4);
		if( !is_writable($save_path) ) Cogumelo::Error("Session save path is not writable: '$save_path'", 4);
		
		//register_shutdown_function('C_SessionManager::Save');
		self::$status = cSESSION_STATUS_OPENED;
	}
	
	public static function Close()
	{
		if( self::$status == cSESSION_STATUS_OPENED )
			self::$data = $_SESSION;
			
		self::$status = cSESSION_STATUS_CLOSED;
		
		return true;
	}
	
	public static function Read($session_id)
	{
		$sess_file = self::session_file($session_id);
		
		self::$id = $session_id;
		
		// first-time visit (no cookie) results as no session data
		if ( file_exists($sess_file) && isset($_COOKIE[session_name()]) )
		{
			$data = file_get_contents($sess_file);
			
			$_SESSION = unserialize($data);
		}
		else
		{
			$data = '';
			$_SESSION = array();
		}
		 
		return $data;
	}
	
	public static function Write($session_id, $session_data = null)
	{
		self::$data = $_SESSION;
		
		
		if( self::$status != cSESSION_STATUS_CLOSED )
			self::Close();
		
		$sess_file = self::session_file($session_id);
		
  		if( $h = fopen($sess_file, "w") )
  		{
    		$return = fwrite( $h, serialize(self::$data) );
    		fclose($h);
    		return $return;
  		}
  		else
    		return false;
	}
	
	public static function Destroy($session_id)
	{
		$sess_file = self::session_file($session_id);
		
		return @ unlink($sess_file);
	}
	
	public static function GarbageCollector($maxlifetime)
	{
		foreach( glob(self::session_file('*')) as $filepath )
		{
		    if(  filemtime($filepath) + $maxlifetime < time()  )
		    	@unlink($filepath);
		}
		return true;
	}
}